// 12. 实现一个Head工具类型，用于获取数组类型的第一个类型。具体的使用示例如下所示：
type Head<T extends Array<any>> = T extends [infer H, ...T[]] ? H: never;
// 测试用例
type H0 = Head<[]> // never
type H1 = Head<[1]> // 1
type H2 = Head<[3, 2]> // 3

// 13. 实现一个Tail工具类型，用于获取数组类型除了第一个类型外，剩余的类型。具体的使用示例如下所示：
type Tail<T extends Array<any>> = T extends [infer H, ...infer R] ? R : never
// 测试用例
type T0 = Tail<[]> // []
type T1 = Tail<[1, 2]> // [2]
type T2 = Tail<[1, 2, 3, 4, 5]> // [2, 3, 4, 5]

// 14. 实现一个Unshift工具类型，用于把指定类型E作为第一个元素添加到 T 数组类型中。具体的使用示例如下所示：
type Unshift<T extends any[], U> = [U, ...T]
// 测试用例
type ArrUnshift0 = Unshift<[], 1>; // [1]
type ArrUnshift1 = Unshift<[1, 2, 3], 0>; // [0, 1, 2, 3]

// 15. 实现一个Shift工具类型，用于移除T数组类型中的第一个类型
type Shift<T extends any[]> = T extends [infer A, ...infer B]? A: never;
// 测试用例
type Shift0 = Shift<[1, 2, 3]> 
type Shift1 = Shift<[string,number,boolean]> 
type Shift2 = Shift<[boolean]> //?

// 16. 实现一个Push工具类型，用于把指定类型E作为第最后一个元素添加到T数组类型中
type Push<T extends any[], V> = [...T, V]
// 测试用例
type ArrPush0 = Push<[], 1> // [1]
type ArrPush1 = Push<[1, 2, 3], 4> // [1, 2, 3, 4]

// 17. 实现一个Includes工具类型，用于判断指定的类型E是否包含在T数组类型中。
type Includes<T extends Array<any>, E> = E extends T[keyof T]? true: false;
// 测试用例
type Includes0 = Includes<[], 1> // false
type Includes1 = Includes<[2, 2, 3, 1], 2> // true
type Includes2 = Includes<[2, 3, 3, 1], 1> // true
type Includes3 = Includes<[2, 'a', false],'a'> // true

// 18. 实现一个UnionToIntersection工具类型，用于把联合类型转换为交叉类型 // 待学习
type UnionToIntersection<U> = (
    U extends unknown ? (disUnio: U) => void: never
  ) extends (merge: infer Inter) => void 
  ? Inter: never
// 测试用例
type UToI0 = UnionToIntersection<string | number> // never
type UToI1 = UnionToIntersection<{ name: string } | { age: number }> // { name: string; } & { age: number; }

// 19. 实现一个OptionalKeys工具类型，用来获取对象类型中声明的可选属性
type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = {
  [P in keyof T]-?: undefined extends T[P]? P: never
}[keyof T]
// undefined extends T[P]? P: never 判断 undefined 是否约束于当前键值 
// （ 可选的格式的： type| undefined, 因此把必选的值变成 never）
// [P in keyof T]-?  把所有的属性变成可选
// { ... }[keyof T]取键值，因为id,age,name的属性类型都为never，取值的时候会被忽略掉,
// 而 never 是不存在的类型，因此剩余的就组成联合类型返回

type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

// 20. 实现一个Curry工具类型，用来实现函数类型的柯里化处理
/**
 * 解析：
 * 1. 先拿 args 数组项和剩余参数合集 [infer A, ...infer B]
 * 2. 通过 extends 判断 P  是否满足 [infer A, ...infer B]，不满足说明没参数，直接返回 () => R
 * 3. 如果有一个以上的参数，则继续递归
 * 4. 判断 B 是否满足 [], 是则 (arg: A) => R, 否则继续 Curry 回调
 * */ 
type Curry<
  F extends (...args: any[]) => any,
  P extends any[] = Parameters<F>, 
  R = ReturnType<F> 
> = P extends [infer A, ...infer B] ? 
  B extends [] ? (arg: A) => R: (arg: A) => Curry<(...args: B) => R>
  :() => R;

type F0 = Curry<() => Date>; // () => Date
type F1 = Curry<(a: number) => Date>; // (arg: number) => Date
type F2 = Curry<(a: number, b: string) => Date>; //  (arg_0: number) => (b: string) => Date

//
function curryThis<Curry>(fn) {
  return function curried(...args) {
    if (args.length < fn.length) {
      return curried(...args.concat(Array.from(arguments)))
    }
    return fn(...args)
  }
}

// 21. 实现一个Merge工具类型，用于把两个类型合并成一个新的类型。
// 第二种类型（SecondType）的Keys将会覆盖第一种类型（FirstType）的Keys
type Foo = { 
  a: number;
  b: string;
};

type Bar = {
  b: number;
};

type Merge<FirstType, SecondType> = {
  [K in keyof (FirstType & SecondType)]: K extends keyof SecondType ? 
  SecondType[K]:
    K extends keyof FirstType? FirstType[K]:  never;
}

type Merge1<FirstType, SecondType> = Omit<FirstType, keyof SecondType> & SecondType


const ab: Merge<Foo, Bar> = { a: 1, b: 2 };
const ab1: Merge1<Foo, Bar> = { a: 1, b: 2 };
